#include "OriRspHeaderSendHandler.h"
#include "AfterOriSendDispatcher.h"
#include "HttpResponseHeader.h"

using namespace log4cplus;

Logger OriRspHeaderSendHandler::log=GetLogger(LOG4CPLUS_TEXT("OriRspHeaderSendHandler"));

ITransHandler::ExecuteResultCode OriRspHeaderSendHandler::Execute(ClientContext &client,OVERLAPPED *ovl)
{
	unsigned int clienSequenceNo=client.SequenceNo();
	LOG4CPLUS_DEBUG_FMT(log,LOG4CPLUS_TEXT("[Client%d]Start to relay original server response header data send."),clienSequenceNo);
	DWORD sendCount=-1;
	DWORD flags;
	BOOL result=::WSAGetOverlappedResult(client.SrcSock(),client.OVL(),&sendCount,true,&flags);
	int errCode=::WSAGetLastError();
	if(result)
	{
		if(sendCount<client.WeakRefBuffer()->len)
		{
			LOG4CPLUS_DEBUG_FMT(log,LOG4CPLUS_TEXT("[Client%d]Send original server response header data not complete,resend."),clienSequenceNo);
			client.WeakRefBuffer()->buf+=sendCount;
			client.WeakRefBuffer()->len-=sendCount;
			::ZeroMemory(client.OVL(),sizeof(OVERLAPPED));
			int sendResult=::WSASend(client.SrcSock(),client.WeakRefBuffer(),1,NULL,0,client.OVL(),NULL);
			errCode=::WSAGetLastError();
			if(sendResult!=0&&errCode!=WSA_IO_PENDING)
			{
				LOG4CPLUS_ERROR_FMT(log,LOG4CPLUS_TEXT("[Client%d]Resend original server response header data failed,error code:%d."),clienSequenceNo,errCode);
				return ITransHandler::ExecuteFatalError;
			}
		}
		else if(client.PartialTransIndex()!=0&&client.PartialTransIndex()<client.HttpResponseHeaderData().TempBuffer().size())
		{
			LOG4CPLUS_DEBUG_FMT(log,LOG4CPLUS_TEXT("[Client%d]Resend(big part) original server response header data."),clienSequenceNo);
			const char *srcIndex=client.HttpResponseHeaderData().TempBuffer().c_str()+client.PartialTransIndex();
			std::string::size_type leftSize=client.HttpResponseHeaderData().TempBuffer().size()-client.PartialTransIndex();
			if(leftSize>client.Buffer()->len)
			{
				memcpy_s(client.Buffer()->buf,client.Buffer()->len,srcIndex,client.Buffer()->len);
				client.SetPartialTransIndex(client.PartialTransIndex()+client.Buffer()->len);
				client.WeakRefBuffer()->len=client.Buffer()->len;
			}
			else
			{
				memcpy_s(client.Buffer()->buf,client.Buffer()->len,srcIndex,leftSize);
				client.SetPartialTransIndex(client.HttpResponseHeaderData().TempBuffer().size());
				client.WeakRefBuffer()->len=leftSize;
			}
			client.WeakRefBuffer()->buf=client.Buffer()->buf;

			::ZeroMemory(client.OVL(),sizeof(OVERLAPPED));
			int sendResult=::WSASend(client.SrcSock(),client.WeakRefBuffer(),1,NULL,0,client.OVL(),NULL);
			int errCode=::WSAGetLastError();
			if(sendResult!=0&&errCode!=WSA_IO_PENDING)
			{
				LOG4CPLUS_ERROR_FMT(log,LOG4CPLUS_TEXT("[Client%d]Resend(big part) original server response header data failed,error code:%d."),
					clienSequenceNo,errCode);
				return ITransHandler::ExecuteFatalError;
			}
		}
		else
		{
			long long &transIndex=client.TranslatedFileIndex();
			transIndex+=client.HttpResponseHeaderData().TempBuffer().size()-client.HttpResponseHeaderData().BodyIndex();
			LOG4CPLUS_DEBUG_FMT(log,LOG4CPLUS_TEXT("[Client%d]Send original server response header data complete,free temp response header buffer,rereceive(send body index:%d)."),
				clienSequenceNo,transIndex);
			client.HttpResponseHeaderData().FreeTempBuffer();
			delete client.SetCurrentHandler(GetNextHandler());
			::ZeroMemory(client.OVL(),sizeof(OVERLAPPED));
			DWORD flags=0;
			int recvResult=::WSARecv(client.DestSock(),client.Buffer(),1,NULL,&flags,client.OVL(),NULL);
			errCode=::WSAGetLastError();
			if(recvResult!=0&&errCode!=WSA_IO_PENDING)
			{
				LOG4CPLUS_ERROR_FMT(log,LOG4CPLUS_TEXT("[Client%d]Begin receive original server response body data failed,error code:%d."),clienSequenceNo,errCode);
				return ITransHandler::ExecuteFatalError;
			}
		}
	}
	else
	{
		LOG4CPLUS_ERROR_FMT(log,LOG4CPLUS_TEXT("[Client%d]Original server response header data send failed,error code:%d."),clienSequenceNo,errCode);
		return ITransHandler::ExecuteFatalError;
	}
	return ITransHandler::ExecuteOK;
}

ITransHandler* OriRspHeaderSendHandler::GetNextHandler()
{
	return new AfterOriSendDispatcher();
}